# utils/socketio_service.py
from datetime import datetime

from flask import session
from flask_socketio import SocketIO, emit
from openai import OpenAI
import os
from models import db
from models.AIInterview import AIInterview
from models.Application import Application
from models.Job import Job
from models.Resume import Resume
from models.ScoreWeight import ScoreWeight
from models.InterviewScores import InterviewScores
import json
from decimal import Decimal

job_info_json = None

# 初始化 OpenAI 客户端
client = OpenAI(
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)

# 面试官系统提示词

system_prompt = """
你是一名专业严谨的 AI 面试官，需完成以下任务：

【角色设定】
1. 面试分为三个阶段：
   - **技术面试**（1 道技术问题）
   - **行为面试**（1 道行为问题）
   - **总结反馈**（1 个总结性问题）
2. 你需要根据以下信息精准生成问题：
   - **职位要求**：{position_info}
   - **候选人简历**：{resume_info}
3. **评分标准（总分 100 分）**：
   - **技术能力（40%）**：掌握岗位相关技术的深度与广度
   - **学习能力（20%）**：学习新技能、适应新环境的能力
   - **团队协作（15%）**：与团队配合、推动项目的能力
   - **问题解决（15%）**：分析问题、制定解决方案的能力
   - **沟通表达（10%）**：清晰阐述观点、有效沟通的能力

【对话规则】
1. **每次只提问 1 个问题**，避免信息过载。
2. **问题间保持逻辑连贯**，逐步深入评估候选人能力。
3. **面试总共 3 轮**，达到 3 轮后自动结束。
4. **用中文提问**，语气专业但友好。

【输出格式要求】
{{
  "current_round": {current_round},
  "phase": "面试阶段"
}}
"""


# 评估报告生成提示词

EVALUATION_PROMPT = """
请基于面试对话历史，生成**结构化评估报告**，对候选人的五项核心能力评分，并提供详细的评估理由。

【输入数据】
面试记录：
{history}
岗位要求：
{position}

【评估标准】
1. 按百分制评分（总分 100 分）。
2. 五个核心维度（分别评分，并提供 50 字左右的评估依据）：
   - 技术能力：候选人对核心技术的掌握程度，能否解决岗位相关的技术问题。
   - 学习能力：是否具备快速学习新技术和适应新环境的能力。
   - 团队协作：是否能与团队成员高效协作，展现出良好的团队精神。
   - 问题解决：是否能够清晰分析问题，并提出合理的解决方案。
   - 沟通表达：表达是否清晰、有逻辑，能否准确传达信息。

【输出 JSON 格式】
{{
  "evaluation_details": [
    {{"dimension": "技术能力", "score": {{score}}, "reason": "..."}},
    {{"dimension": "学习能力", "score": {{score}}, "reason": "..."}},
    {{"dimension": "团队协作", "score": {{score}}, "reason": "..."}},
    {{"dimension": "问题解决", "score": {{score}}, "reason": "..."}},
    {{"dimension": "沟通表达", "score": {{score}}, "reason": "..."}}
  ]
}}
"""


# OpenAI 流式对话

def stream_chat(messages):
    answer_content = ""

    stream = client.chat.completions.create(
        model="deepseek-v3",
        messages=messages,
        stream=True
    )

    for chunk in stream:
        if not getattr(chunk, 'choices', None):
            continue

        delta = chunk.choices[0].delta

        if not hasattr(delta, 'content'):
            continue

        if not getattr(delta, 'content', None):
            continue

        answer_content += delta.content

    return answer_content


# 解析简历 & 岗位信息

def analyze_resume(resume_id, job_id):
    resume = Resume.query.filter_by(resume_id=resume_id).first()
    job = Job.query.filter_by(job_id=job_id).first()
    job_details = {
        'title': job.title,
        'job_type': job.job_type,
        'description': job.description,
        'requirements': job.requirements,
        'min_salary': job.min_salary,
        'max_salary': job.max_salary
    }
    return job_details, resume.parsed_data


# 生成评估报告

def generate_evaluation_report(history, position_info):
    evaluation_message = EVALUATION_PROMPT.format(
        history=history,
        position=position_info
    )
    messages = [{"role": "system", "content": evaluation_message}]

    # 获取原始响应
    raw_response = stream_chat(messages)

    # 尝试提取 JSON 部分
    try:
        # 查找第一个 { 和最后一个 } 的位置
        start_idx = raw_response.find('{')
        end_idx = raw_response.rfind('}') + 1

        if start_idx != -1 and end_idx != -1:
            json_str = raw_response[start_idx:end_idx]
            # 验证是否为有效的 JSON
            json.loads(json_str)
            return json_str
        else:
            raise ValueError("未找到有效的 JSON 格式")

    except (json.JSONDecodeError, ValueError) as e:
        print(f"解析评估报告失败: {str(e)}")
        print(f"原始响应: {raw_response}")
        raise


# 初始化 SocketIO

def initialize_socketio(app):
    socketio = SocketIO(app)

    @socketio.on('start_interview')
    def handle_start_interview(data):
        try:
            # 初始化会话存储
            if 'conversation_log' not in session:
                session['conversation_log'] = []
            conversation_log = session['conversation_log']
            
            # 检查是否已有进行中的面试
            existing_interview = AIInterview.query.filter_by(
                application_id=session['application_id'],
                end_time=None
            ).first()
            
            if existing_interview:
                # 如果有未完成的面试，继续使用该记录
                session['interview_id'] = existing_interview.interview_id
                emit('interview_status', {'status': 'continued', 'interview_id': existing_interview.interview_id})
            else:
                # 创建新的面试记录
                new_interview = AIInterview(
                    application_id=session['application_id'],
                    start_time=datetime.now()
                )
                db.session.add(new_interview)
                db.session.commit()
                
                session['interview_id'] = new_interview.interview_id
                emit('interview_status', {'status': 'started', 'interview_id': new_interview.interview_id})
            
            # 查询 Application 表
            application = Application.query.filter_by(application_id=session['application_id']).first()
            if not application:
                emit('error', {'message': '未找到对应的申请记录'})
                return

            # 获取简历和职位信息
            job_info_json, resume_json = analyze_resume(application.resume_id, application.job_id)
            session['job_info_json'] = job_info_json  # 保存到session

            # 初始化面试对话
            initial_message = system_prompt.format(
                position_info=job_info_json,
                resume_info=resume_json,
                current_round=1
            )

            # 初始化会话历史
            conversation_log = [
                {"role": "system", "content": initial_message},
                {"role": "user", "content": "我准备好了，面试开始"}
            ]
            session['conversation_log'] = conversation_log
            session.modified = True  # 确保session被标记为已修改

            # 生成第一个问题
            answer = stream_chat(conversation_log)
            conversation_log.append({"role": "assistant", "content": answer})
            session['conversation_log'] = conversation_log
            session.modified = True

            emit('new_message', {'role': 'assistant', 'content': answer})

        except Exception as e:
            db.session.rollback()
            emit('error', {'message': f'开始面试失败: {str(e)}'})
            return

    @socketio.on('user_input')
    def handle_user_input(data):
        try:
            # 从session获取会话历史
            if 'conversation_log' not in session:
                emit('error', {'message': '面试会话未初始化'})
                return
            conversation_log = session['conversation_log']
            
            user_input = data.get('content')
            conversation_log.append({"role": "user", "content": user_input})
            session['conversation_log'] = conversation_log
            session.modified = True

            # 计算当前轮次
            current_round = (len(conversation_log) - 2) // 2
            if current_round == 0:
                current_round = 1

            # 检查是否达到最大轮次
            max_rounds = 2
            if current_round == max_rounds:
                print(2222)
                # 获取对话历史
                history = "\n".join([f"{msg['role']}: {msg['content']}" for msg in conversation_log[2:]])
                
                # 从session获取job_info_json
                job_info_json = session.get('job_info_json')
                if not job_info_json:
                    emit('error', {'message': '面试信息丢失'})
                    return
                
                # 生成评估报告
                evaluation_report = generate_evaluation_report(history, job_info_json)
                print(evaluation_report)
                
                try:
                    # 解析评估报告 JSON
                    evaluation_data = json.loads(evaluation_report)
                    print(evaluation_data)
                    
                    # 获取面试记录
                    interview_id = session.get('interview_id')
                    interview = AIInterview.query.get(interview_id)

                    
                    if interview:
                        # 更新面试记录
                        interview.history = history
                        interview.evaluation = evaluation_data
                        interview.end_time = datetime.now()
                        
                        # 获取评分并确保类型转换为 float
                        scores = {}
                        for item in evaluation_data['evaluation_details']:
                            dimension = item['dimension']
                            # 确保分数是浮点数类型
                            score = float(item['score'])
                            if dimension == '技术能力':
                                scores['technical_ability'] = score
                            elif dimension == '学习能力':
                                scores['learning_ability'] = score
                            elif dimension == '团队协作':
                                scores['team_collaboration'] = score
                            elif dimension == '问题解决':
                                scores['problem_solving'] = score
                            elif dimension == '沟通表达':
                                scores['communication_expression'] = score


                        print(scores)
                        # 验证分数范围
                        for score_value in scores.values():
                            if not (0 <= score_value <= 100):
                                raise ValueError(f"分数必须在0-100范围内: {score_value}")

                        # 使用 ORM 模型创建分数记录，确保类型正确
                        interview_scores = InterviewScores(
                            interview_id=int(interview_id),  # 确保是整数
                            technical_ability=float(scores['technical_ability']),
                            learning_ability=float(scores['learning_ability']),
                            team_collaboration=float(scores['team_collaboration']),
                            problem_solving=float(scores['problem_solving']),
                            communication_expression=float(scores['communication_expression'])
                        )
                        
                        db.session.add(interview_scores)
                        
                        # 获取职位特定的权重设置
                        application = Application.query.get(interview.application_id)
                        job = Job.query.get(application.job_id)
                        
                        # 修改为使用job_id获取权重设置
                        job_weights = ScoreWeight.query.filter_by(job_id=job.job_id).all()

                        # 判断是否找到职位特定的权重设置
                        if job_weights and len(job_weights) > 0:
                            # 使用职位特定的权重进行计算
                            total_score = 0
                            
                            for weight in job_weights:
                                if weight.weight_name == '技术能力':
                                    total_score += float(scores['technical_ability']) * float(weight.weight_value)
                                elif weight.weight_name == '学习能力':
                                    total_score += float(scores['learning_ability']) * float(weight.weight_value)
                                elif weight.weight_name == '团队协作':
                                    total_score += float(scores['team_collaboration']) * float(weight.weight_value)
                                elif weight.weight_name == '问题解决':
                                    total_score += float(scores['problem_solving']) * float(weight.weight_value)
                                elif weight.weight_name == '沟通表达':
                                    total_score += float(scores['communication_expression']) * float(weight.weight_value)
                            
                            # 更新总分
                            interview.overall_score = total_score
                        else:
                            # 如果没有找到职位特定的权重设置，则使用默认权重
                            # 获取公司权重设置（作为备选）
                            company_weights = ScoreWeight.query.filter_by(company_id=job.company_id).first()
                        
                        # 设置权重并确保转换为浮点数
                        if not company_weights:
                            weights = {
                                'technical_weight': 0.40,
                                'learning_weight': 0.20,
                                'team_weight': 0.15,
                                'problem_solving_weight': 0.15,
                                'communication_weight': 0.10
                            }
                        else:
                            weights = {
                                'technical_weight': float(company_weights.technical_weight),
                                'learning_weight': float(company_weights.learning_weight),
                                'team_weight': float(company_weights.team_weight),
                                'problem_solving_weight': float(company_weights.problem_solving_weight),
                                'communication_weight': float(company_weights.communication_weight)
                            }
                        
                        # 计算总分
                        overall_score = float(
                            scores['technical_ability'] * weights['technical_weight'] +
                            scores['learning_ability'] * weights['learning_weight'] +
                            scores['team_collaboration'] * weights['team_weight'] +
                            scores['problem_solving'] * weights['problem_solving_weight'] +
                            scores['communication_expression'] * weights['communication_weight']
                        )
                        
                        # 更新总分
                        interview.overall_score = overall_score
                        
                        # 提交所有更改
                        db.session.commit()
                        
                        # 在评估报告发送之后，更新申请状态
                        try:
                            # 更新 Application 状态
                            application = Application.query.get(interview.application_id)
                            if application:
                                application.status = '待定'
                                db.session.commit()
                            
                            # 发送评估报告和结束通知给前端
                            emit('evaluation_report', {
                                'report': evaluation_report,
                                'overall_score': overall_score,
                                'status': 'completed'  # 添加状态标识
                            })
                            
                        except Exception as e:
                            db.session.rollback()
                            emit('error', {'message': f'更新申请状态失败: {str(e)}'})
                            return
                        
                        # 清理session中的会话数据
                        session.pop('conversation_log', None)
                        session.pop('job_info_json', None)
                        session.modified = True
                        
                        return  # 终止对话

                    else:
                        emit('error', {'message': '未找到面试记录'})
                    
                except ValueError as e:
                    db.session.rollback()
                    emit('error', {'message': f'数据类型错误: {str(e)}'})
                    return
                except Exception as e:
                    db.session.rollback()
                    emit('error', {'message': f'保存评估结果失败: {str(e)}'})
                    return
                    
                # 清理session中的会话数据
                session.pop('conversation_log', None)
                session.pop('job_info_json', None)
                session.modified = True
                
                return  # 终止对话

            # 生成新的面试问题
            answer = stream_chat(conversation_log)
            conversation_log.append({"role": "assistant", "content": answer})
            session['conversation_log'] = conversation_log
            session.modified = True
            
            emit('new_message', {'role': 'assistant', 'content': answer})

        except Exception as e:
            emit('error', {'message': f'处理回答失败: {str(e)}'})

    return socketio
